package com.dsteiner.xelavos.client;


import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.dsteiner.widgets.client.JsUtil;
import com.dsteiner.widgets.client.OAuthPage;
import com.dsteiner.widgets.client.PopupOverlayWidget;
import com.dsteiner.widgets.client.controller.MessageController;
import com.dsteiner.widgets.client.controller.PopupOverlayController;
import com.dsteiner.widgets.client.domain.Distinct;
import com.dsteiner.widgets.client.domain.ModelObject;
import com.dsteiner.widgets.client.event.Event;
import com.dsteiner.widgets.client.event.EventListener;
import com.dsteiner.widgets.client.event.EventManagerImpl;
import com.dsteiner.widgets.client.model.PopupOverlayModel;
import com.dsteiner.widgets.client.resources.WidgetsResources;
import com.dsteiner.widgets.client.rpc.CrudResult;
import com.dsteiner.widgets.client.rpc.DistinctRequest;
import com.dsteiner.widgets.client.rpc.DistinctService;
import com.dsteiner.xelavos.client.AuthenticationWidget.UserWidget;
import com.dsteiner.xelavos.client.ConfirmPopupWidget.ConfirmPopupModel;
import com.dsteiner.xelavos.client.ContactWidget.ContactModel;
import com.dsteiner.xelavos.client.DashletWidget.DashletModel;
import com.dsteiner.xelavos.client.constants.Constants;
import com.dsteiner.xelavos.client.controller.DashletDisplayController;
import com.dsteiner.xelavos.client.controller.DataController;
import com.dsteiner.xelavos.client.controller.PlaceController;
import com.dsteiner.xelavos.client.controller.WindowController;
import com.dsteiner.xelavos.client.domain.User;
import com.dsteiner.xelavos.client.event.CreateObjectEvent;
import com.dsteiner.xelavos.client.event.DistinctEvent;
import com.dsteiner.xelavos.client.event.SearchEvent;
import com.dsteiner.xelavos.client.model.AuthenticationModel;
import com.dsteiner.xelavos.client.model.DataModel;
import com.dsteiner.xelavos.client.model.MainTabModel;
import com.dsteiner.xelavos.client.model.MyEntriesModel;
import com.dsteiner.xelavos.client.model.SearchModel;
import com.dsteiner.xelavos.client.model.TopNewModel;
import com.dsteiner.xelavos.client.model.UserStatsModel;
import com.dsteiner.xelavos.client.resources.XelavosResources;
import com.dsteiner.xelavos.client.rpc.DataService;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.dom.client.StyleInjector;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.RootPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Xelavos implements EntryPoint, Constants {

	final RootPanel contentTabRootPanel = RootPanel.get(ID_CONTENT_TAB);
	final RootPanel contentUsersRootPanel = RootPanel.get(ID_CONTENT_USERS);
	final RootPanel contentMainRootPanel = RootPanel.get(ID_CONTENT_MAIN);
	final RootPanel loadingMsgRootPanel = RootPanel.get("loadingmsg");
	final RootPanel contentRootPanel = RootPanel.get(ID_CONTENT);
	final SearchModel searchModel = new SearchModel();
	final MainTabModel mainTabModel = new MainTabModel();
	private List<Event> events = new ArrayList<Event>();
	private DashletModel dashletModel = new DashletModel();
	EventListener<Event> eventListener = new EventListener<Event>(){
		public void onEvent(Event event) {
			events.add(event);
		}
	};
	
	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
        new OAuthPage();
	}
		public void onModuleLoad2() {
//		DataService.Util.getInstance().clearCache(new AsyncCallback<Void>(){
//			public void onFailure(Throwable arg0) {
//				arg0.printStackTrace();
//			}
//			public void onSuccess(Void arg0) {
//				System.out.println(".onSuccess()");
//			}
//		});
		System.out.println("Xelavos.onModuleLoad()");
		EventManagerImpl.getInstance().registerListener(SearchEvent.class, eventListener);
		EventManagerImpl.getInstance().registerListener(CreateObjectEvent.class, eventListener);
		MessageController.getInstance().activate();
//		createDistincts();
		DistinctService.Util.getInstance().getDistincts(new DistinctRequest(6, Constants.Util.getDistinctableDashletList()), 
				new AsyncCallback<List<Distinct>>(){
			public void onFailure(Throwable arg0) {
				arg0.printStackTrace();
			}
			public void onSuccess(List<Distinct> distincts) {
				EventManagerImpl.getInstance().fireEvent(new DistinctEvent(distincts));
			}
		});
		
		GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler(){
			public void onUncaughtException(Throwable e) {
				e.printStackTrace();
			}
		});
		try{
			StyleInjector.injectStylesheet(XelavosResources.INSTANCE.css().getText());
			StyleInjector.injectStylesheet(WidgetsResources.INSTANCE.cssBoxSizing().getText());
			
			DashletDisplayController dashletDisplayController = new DashletDisplayController();
			DashletWidget dashletWidget = new DashletWidget(dashletModel, searchModel, mainTabModel);
			PopupOverlayModel popupOverlayModel = new PopupOverlayModel();
			PopupOverlayWidget popupOverlayWidget = new PopupOverlayWidget(popupOverlayModel);
			popupOverlayModel.setContentWidget(dashletWidget);
			PopupOverlayController.showAtCenter(popupOverlayModel);
			
			dashletDisplayController.registerPopupOverlayModel(popupOverlayModel);
			dashletDisplayController.registerDashletModel(dashletModel);
			dashletDisplayController.registerJsUtil(JsUtil.getInstance());
			
			popupOverlayWidget.addStyleName(XelavosResources.INSTANCE.css().dashletPopup());
			dashletModel.setVisible(true);
			
			GWT.runAsync(new RunAsyncCallback(){
				public void onFailure(Throwable reason) {
					reason.printStackTrace();
				}
				public void onSuccess() {
					loadingMsgRootPanel.setVisible(false);
					initUi();
				}
			});
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}

	private void initUi() {
		final TopNewModel topNewModel = new TopNewModel();
		final AuthenticationModel authenticationModel = new AuthenticationModel();
		final MyEntriesModel myEntriesModel = new MyEntriesModel();
		final UserStatsModel userStatsModel = new UserStatsModel();
		
		WindowController windowController = new WindowController();
		windowController.registerAuthenticationModel(authenticationModel);
		windowController.registerContentTabRootPanel(contentTabRootPanel);
		windowController.registerContentRootPanel(contentRootPanel);
		windowController.registerContentMainRootPanel(contentMainRootPanel);
		windowController.registerJsUtil(JsUtil.getInstance());
		
		DataController dataController = new DataController();
		DataModel dataModel = new DataModel();
		dataController.registerTopNewModel(topNewModel);
		dataController.registerMainTabModel(mainTabModel);
		dataController.registerDataModel(dataModel);
		dataController.registerSearchModel(searchModel);
		dataController.registerAuthenticationModel(authenticationModel);
		dataController.registerMyEntriesModel(myEntriesModel);
		dataController.registerEventManager(EventManagerImpl.getInstance());
		dataController.registerUserStatsModel(userStatsModel);
		
		DeferredCommand.addCommand(new Command(){
			public void execute() {
				AuthenticationWidget loginWidget = new AuthenticationWidget(authenticationModel, 
						myEntriesModel);
				RootPanel.get(ID_LOGIN).add(loginWidget);
				
				ContactModel contactModel = new ContactModel();
				ContactWidget contactWidget = new ContactWidget(contactModel);
				RootPanel.get(ID_CONTACT).add(contactWidget);
				
				UserStatsWidget userStatsWidget = new UserStatsWidget(userStatsModel, authenticationModel);
				RootPanel.get(ID_USER_STATS).add(userStatsWidget);
				
				UserWidget userWidget = new UserWidget(authenticationModel, myEntriesModel);
				RootPanel.get(ID_USER_INFO).add(userWidget);
				
				String userId = JsUtil.getInstance().getCookie(Constants.COOKIE_NAME_USER_ID);
				if(userId != null && !"null".equals(userId)){
					DataService.Util.getInstance().getObjectById(userId, User.class.getName(), 
							new AsyncCallback<CrudResult<ModelObject>>(){
						public void onFailure(Throwable caught) {
							caught.printStackTrace();
						}
						public void onSuccess(CrudResult result) {
							User user = (User) result.getModelObject();
							authenticationModel.setUser(user);
							JsUtil.getInstance().trackGAVar(Constants.Util.getUserGAVar(user));
						}
					});
				}
				
			}
		});
		
		DeferredCommand.addCommand(new Command(){
			public void execute() {
				EventManagerImpl.getInstance().removeListener(SearchEvent.class, eventListener);
				EventManagerImpl.getInstance().removeListener(CreateObjectEvent.class, eventListener);
				final SearchWidget searchWidget = new SearchWidget(searchModel, 
						authenticationModel, mainTabModel, topNewModel);
				FlowPanel contentMainPanel = new FlowPanel();
				contentMainPanel.add(searchWidget);
				contentMainRootPanel.add(contentMainPanel);
				
				ConfirmPopupModel confirmPopupModel = new ConfirmPopupModel();
				ConfirmPopupWidget confirmPopup = new ConfirmPopupWidget(confirmPopupModel);
			}
		});
		
		DeferredCommand.addCommand(new Command(){
			public void execute() {
				MainTabWidget mainTabWidget = new MainTabWidget(mainTabModel, searchModel);
				contentTabRootPanel.add(mainTabWidget);
			}
		});
		
		DeferredCommand.addCommand(new Command(){
			public void execute() {
				TopNewWidget usersWidget = new TopNewWidget(topNewModel, mainTabModel, authenticationModel);
				contentUsersRootPanel.add(usersWidget);
			}
		});
		
		DeferredCommand.addCommand(new Command(){
			public void execute() {
				for (Event event : events) {
					EventManagerImpl.getInstance().fireEvent(event);
				}
				events.clear();
				PlaceController placeController = new PlaceController();
				placeController.registerEventManager(EventManagerImpl.getInstance());
				History.fireCurrentHistoryState();
			}
		});
	}

	private void createDistincts(){
		Distinct[] distinctables = Constants.Util.getDistinctableDashletList();
		for (Distinct distinct : distinctables) {
			createDistincts(distinct.getClassName(), distinct.getProperty());
		}
	}

	private void createDistincts(String className, String property) {
		DistinctService.Util.getInstance().createDistincts(className, property, new AsyncCallback<Collection<Distinct>>(){
			public void onFailure(Throwable arg0) {
				arg0.printStackTrace();
			}
			public void onSuccess(Collection<Distinct> distincts) {
				System.out.println(".onSuccess():"+distincts);
			}
		});
	}
	
}
